package com.ztc.common.wechatpay;

import com.ztc.common.util.MD5Util;
import com.ztc.common.wechatpay.config.WeChatConfig;
import com.ztc.common.wechatpay.model.RefundParameter;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.ResourceUtils;

import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.Map;
import java.util.TreeMap;

import static com.ztc.common.wechatpay.config.WeChatConfig.*;


/**
 * 调起微信支付类.
 *
 */
public final class WeChatPay {

    private static final Logger LOGGER = LogManager.getLogger(WeChatPay.class);

    private WeChatPay() {

    }

    /**
     * 退款申请
     *
     * @return
     */
    public static boolean refundApply(RefundParameter refundParameter,Integer payMode) throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, KeyManagementException {
        boolean isTrue = false;
        String path = "classpath:apiclient_cert_lvxingshe.p12";
        refundParameter.setMchId(WeChatConfig.JS_MCH_ID);
        refundParameter.setPartnerKey(WeChatConfig.JS_PARTNER_KEY);
        switch (payMode) {
            case 1:
                refundParameter.setAppId(WeChatConfig.APP_APP_ID);
                refundParameter.setMchId(WeChatConfig.APP_MCH_ID);
                refundParameter.setPartnerKey(WeChatConfig.APP_PARTNER_KEY);
                path = "classpath:apiclient_cert_app.p12";
                break;
            case 2:
                refundParameter.setAppId(WeChatConfig.JS_APP_ID);
                break;
            case 3:
                refundParameter.setAppId(WeChatConfig.WEB_APP_ID);
                break;
        }
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        FileInputStream instream = new FileInputStream(ResourceUtils.getFile(path));
        try {
            keyStore.load(instream, refundParameter.getMchId().toCharArray());
        } finally {
            instream.close();
        }
        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, refundParameter.getMchId().toCharArray()).build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

        HttpPost httpPost = new HttpPost(REFUND_URL);
        String xml = getRundPackageParams(refundParameter);
        StringEntity entity;
        try {
            entity = new StringEntity(xml, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse httpResponse;
            // post请求
            httpResponse = httpclient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            if (httpEntity != null) {
                // 打印响应内容
                String result = EntityUtils.toString(httpEntity, "UTF-8");
                XmlMapper xmlMapper = new XmlMapper();
                Map<String, String> xmlMap = xmlMapper.readValue(result, Map.class);
                if ("SUCCESS".equals(xmlMap.get("return_code")) && "OK".equals(xmlMap.get("return_msg"))) {
                    isTrue = true;
                }
            }
            // 释放资源
            httpclient.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return isTrue;
    }

    /**
     * 生成退款请求发送参数XML
     *
     * @param refundParameter
     * @return
     */
    private static String getRundPackageParams(RefundParameter refundParameter) {
        TreeMap<String, String> treeMap = new TreeMap<String, String>();
        treeMap.put("appid", refundParameter.getAppId());
        treeMap.put("mch_id", refundParameter.getMchId());
        treeMap.put("nonce_str", refundParameter.getNonceStr());
        treeMap.put("out_trade_no", refundParameter.getOutTradeNo());
        treeMap.put("out_refund_no", refundParameter.getOutRefundNo());
        treeMap.put("total_fee", String.valueOf(refundParameter.getTotalFee()));
        treeMap.put("refund_fee", String.valueOf(refundParameter.getRefundFee()));
        treeMap.put("refund_desc", refundParameter.getRefundDesc());
        StringBuffer sb = new StringBuffer();
        for (String key : treeMap.keySet()) {
            sb.append(key).append("=").append(treeMap.get(key)).append("&");
        }
        sb.append("key=" + refundParameter.getPartnerKey());
        refundParameter.setSign(MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase());
        treeMap.put("sign", refundParameter.getSign());
        StringBuffer xml = new StringBuffer();
        xml.append("<xml>\n");
        for (Map.Entry<String, String> entry : treeMap.entrySet()) {
            xml.append("<" + entry.getKey() + "><![CDATA[").append(entry.getValue()).append("]]></" + entry.getKey() + ">\n");
        }
        xml.append("</xml>");
        LOGGER.debug("退款请求发送发送参数XML" + xml.toString());
        return xml.toString();
    }
}
